﻿using CommonLibrary;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using System;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using System.Security.Cryptography;
using System.Text;
using System.Threading.Tasks;
using System.Xml;

namespace Model
{
   
    public class WxPayObjectV2
    {
        public WxPayObjectV2(int orderid)
        {
            using (DbHelper db = new DbHelper())
            {
                db.AddParameter("@orderid", orderid);
                DataTable dt = db.ExecuteProcedureWithOneTable<DataTable>("P_UnifiedOrder");
                if (dt == null || dt.Rows == null || dt.Rows.Count != 1)
                    throw new Exception("微信统一下单出错");
                
                appid = dt.Rows[0]["appid"].ToString();
                attach = dt.Rows[0]["attach"].ToString();
                body = dt.Rows[0]["body"].ToString();
                mch_id = dt.Rows[0]["mchid"].ToString();
                nonce_str = Guid.NewGuid().ToString("N").ToLower();
                notify_url = dt.Rows[0]["notifyurl"].ToString();
                openid = dt.Rows[0]["openid"].ToString();
                ip = dt.Rows[0]["ip"].ToString();
                total_fee = Convert.ToInt32(dt.Rows[0]["totalfee"]);
                mch_secrect = dt.Rows[0]["mchsecrect"].ToString();
                this.out_trade_no = dt.Rows[0]["out_trade_no"].ToString();
            }
        }

        public object ToPay()
        {
            string getdata = "";
            try
            {
                string strA = "appid=" + appid + "&attach=" + attach + "&body=" + body + "&mch_id=" + mch_id + "&nonce_str=" + nonce_str + "&notify_url=" + notify_url + "&openid=" + openid + "&out_trade_no=" + out_trade_no + "&spbill_create_ip=" + ip + "&total_fee=" + total_fee + "&trade_type=JSAPI";
                string strk = strA + "&key=" + mch_secrect;  //key为商户平台设置的密钥key(假)
                string strMD5 = WxCommonObj.MD5(strk).ToUpper();//MD5签名

                //string strHash=HmacSHA256("sha256",strmd5).ToUpper();   //签名方式只需一种(MD5 或 HmacSHA256     【支付文档需仔细看】)

                //签名
                var formData = "<xml>";
                formData += "<appid>" + appid + "</appid>";//appid
                formData += "<attach>" + attach + "</attach>"; //附加数据(描述)
                formData += "<body>" + body + "</body>";//商品描述
                formData += "<mch_id>" + mch_id + "</mch_id>";//商户号
                formData += "<nonce_str>" + nonce_str + "</nonce_str>";//随机字符串，不长于32位。
                formData += "<notify_url>" + notify_url + "</notify_url>";//通知地址
                formData += "<openid>" + openid + "</openid>";//openid
                formData += "<out_trade_no>" + out_trade_no + "</out_trade_no>";//商户订单号    --待
                formData += "<spbill_create_ip>" + ip + "</spbill_create_ip>";//终端IP  --用户ip
                formData += "<total_fee>" + total_fee + "</total_fee>";//支付金额单位为（分）
                formData += "<trade_type>JSAPI</trade_type>";//交易类型(JSAPI--公众号支付)
                formData += "<sign>" + strMD5 + "</sign>"; //签名
                formData += "</xml>";

                getdata = WxCommonObj.sendPost(WxConstObject.unifiedorder_v2, formData);

                //获取xml数据
                XmlDocument doc = new XmlDocument();
                doc.LoadXml(getdata);
                //xml格式转json
                string json = Newtonsoft.Json.JsonConvert.SerializeXmlNode(doc);

                JObject jo = (JObject)JsonConvert.DeserializeObject(json);
                string return_code = jo["xml"]["return_code"]["#cdata-section"].ToString();
                if(return_code != "SUCCESS")
                {
                    throw new Exception(jo["xml"]["return_msg"]["#cdata-section"].ToString());
                }
                
                string result_code = jo["xml"]["result_code"]["#cdata-section"].ToString();
                if(result_code != "SUCCESS")
                {
                    throw new Exception(jo["xml"]["err_code_des"]["#cdata-section"].ToString());
                }
                string prepay_id = jo["xml"]["prepay_id"]["#cdata-section"].ToString();
                //时间戳
                string _time = getTime().ToString();

                //再次签名返回数据至小程序
                string strB = "appId=" + appid + "&nonceStr=" + nonce_str + "&package=prepay_id=" + prepay_id + "&signType=MD5&timeStamp=" + _time + "&key=" + mch_secrect;

                //wx自己写的一个类
                object w = new
                {
                    timeStamp = _time,
                    nonceStr = nonce_str,
                    prepay_id = prepay_id,
                    paySign = WxCommonObj.MD5(strB).ToUpper()
                };

                //向小程序返回json数据
                return w;
            }
            catch (Exception e)
            {
                LogHelper.WriteLog("微信统一下单报错", e);
                using (DbHelper db = new DbHelper())
                {
                    db.AddParameter("@logtype", "error");
                    db.AddParameter("@function", "WxPayObject.ToPay");
                    db.AddParameter("@requestpara", "订单号：" + out_trade_no);
                    db.AddParameter("@responsedata", getdata);
                    db.AddParameter("@errmsg", "");
                    db.AddParameter("@stacktrace", "");

                    db.ExecuteProcedure<DataTable>("P_AddLog");
                }
                throw new Exception(e.Message);
            }
            
        }

        private static long getTime()
         {
             TimeSpan cha = (DateTime.Now - TimeZone.CurrentTimeZone.ToLocalTime(new System.DateTime(1970, 1, 1)));
             long t = (long)cha.TotalSeconds;
             return t;
         }

        private string appid { get; set; }
        private string attach { get; set; }
        private string body { get; set; }
        private string mch_id { get; set; }
        private string nonce_str { get; set; }
        private string notify_url { get; set; }
        private string openid { get; set; }
        private string spbill_create_ip { get; set; }
        private int total_fee { get; set; }
        private string strMD5 { get; set; }
        private string ip { get; set; }
        private string mch_secrect { get; set; }

        private string out_trade_no { get; set; }

        
    }
    public class WxQueryPayResult
    {
        public WxQueryPayResult(int orderid)
        {
            this.orderid = orderid;
            using (DbHelper db = new DbHelper())
            {
                db.AddParameter("@orderid", orderid);
                DataTable dt = db.ExecuteProcedureWithOneTable<DataTable>("P_WxQueryPayResult");
                if (dt == null || dt.Rows == null || dt.Rows.Count != 1)
                    throw new Exception("微信查询订单支付结果出错");

                appid = dt.Rows[0]["appid"].ToString();
                mch_id = dt.Rows[0]["mchid"].ToString();
                mch_secrect = dt.Rows[0]["mchsecrect"].ToString();

                nonce_str = Guid.NewGuid().ToString("N").ToLower();
                out_trade_no = dt.Rows[0]["out_trade_no"].ToString();
            }
        }
        public bool Query()
        {
            string getdata = "";
            try
            {
                string strA = "appid=" + appid + "&mch_id=" + mch_id + "&nonce_str=" + nonce_str + "&out_trade_no=" + out_trade_no;
                string strk = strA + "&key=" + mch_secrect;  //key为商户平台设置的密钥key(假)
                string strMD5 = WxCommonObj.MD5(strk).ToUpper();//MD5签名

                //签名
                var formData = "<xml>";
                formData += "<appid>" + appid + "</appid>";//appid
                formData += "<mch_id>" + mch_id + "</mch_id>";//商户号
                formData += "<nonce_str>" + nonce_str + "</nonce_str>";//随机字符串，不长于32位。
                formData += "<out_trade_no>" + out_trade_no + "</out_trade_no>";//商户订单号  transaction_id  
                formData += "<sign>" + strMD5 + "</sign>"; //签名
                formData += "</xml>";

                getdata = WxCommonObj.sendPost(WxConstObject.orderquery, formData);

                //获取xml数据
                XmlDocument doc = new XmlDocument();
                doc.LoadXml(getdata);
                //xml格式转json
                string json = Newtonsoft.Json.JsonConvert.SerializeXmlNode(doc);

                JObject jo = (JObject)JsonConvert.DeserializeObject(json);
                string return_code = jo["xml"]["return_code"]["#cdata-section"].ToString();
                if (return_code != "SUCCESS")
                {
                    return false;
                    //throw new Exception(jo["xml"]["return_msg"]["#cdata-section"].ToString());
                }
                string result_code = jo["xml"]["result_code"]["#cdata-section"].ToString();
                if (result_code != "SUCCESS")
                {
                    return false;
                    //throw new Exception(jo["xml"]["err_code_des"]["#cdata-section"].ToString());
                }
                string trade_state = jo["xml"]["trade_state"]["#cdata-section"].ToString();

                if (!string.IsNullOrEmpty(trade_state) && trade_state.ToUpper() == "SUCCESS")
                {
                    using (DbHelper db = new DbHelper())
                    {
                        db.AddParameter("@orderid", orderid);
                        db.AddParameter("@status", 20);
                        db.AddParameter("@expressno", "");
                        db.AddParameter("@expresscompany", "");
                        db.ExecuteProcedure<DataTable>("P_UpdateOrderStatus");
                    }
                    return true;
                }
                else
                    return false;
            }
            catch (Exception e)
            {
                LogHelper.WriteLog("微信查询订单支付结果报错", e);
                using (DbHelper db = new DbHelper())
                {
                    db.AddParameter("@logtype", "error");
                    db.AddParameter("@function", "WxQueryPayResult.Query");
                    db.AddParameter("@requestpara", "订单号：" + out_trade_no);
                    db.AddParameter("@responsedata", getdata);
                    db.AddParameter("@errmsg", "");
                    db.AddParameter("@stacktrace", "");

                    db.ExecuteProcedure<DataTable>("P_AddLog");
                }
                throw new Exception(e.Message);
            }
        }
        private int orderid { get; set; }
        private string appid { get; set; }
        private string mch_id { get; set; }
        private string out_trade_no { get; set; }
        private string nonce_str { get; set; }
        private string sign { get; set; }
        private string mch_secrect { get; set; }
    }
    public static class WxCommonObj
    {
        public static string sendPost(string URL, string urlArgs)
        {
            System.Net.WebClient wCient = new System.Net.WebClient();
            wCient.Headers.Add("Content-Type", "application/x-www-form-urlencoded");
            //byte[] postData = System.Text.Encoding.ASCII.GetBytes(urlArgs);  如果微信签名中有中文会签名失败
            byte[] postData = System.Text.Encoding.UTF8.GetBytes(urlArgs);
            byte[] responseData = wCient.UploadData(URL, "POST", postData);

            string returnStr = System.Text.Encoding.UTF8.GetString(responseData);//返回接受的数据 

            using (DbHelper db = new DbHelper())
            {
                db.AddParameter("@logtype", "info");
                db.AddParameter("@function", "WxCommonObj.SendPost");
                db.AddParameter("@requestpara", urlArgs);
                db.AddParameter("@responsedata", returnStr);
                db.AddParameter("@errmsg", "");
                db.AddParameter("@stacktrace", "");

                db.ExecuteProcedure<DataTable>("P_AddLog");
            }

            return returnStr;
        }

        /// <summary>
        /// MD5签名方法
        /// </summary>
        /// <param name="inputText">加密参数</param>
        /// <returns></returns>
        public static string MD5(string inputText)
        {
            MD5 md5 = new MD5CryptoServiceProvider();
            byte[] fromData = System.Text.Encoding.UTF8.GetBytes(inputText);
            byte[] targetData = md5.ComputeHash(fromData);
            string byte2String = null;

            for (int i = 0; i < targetData.Length; i++)
            {
                byte2String += targetData[i].ToString("x2");
            }

            return byte2String;
        }
    }
}
